// Copyright (C) Calum Grant 2008

namespace dynamic
{
	namespace gc
	{
		class garbage_collector;
	}

	class var;
	class pickler;
	class unpickler;
	class shared_var_impl;
	typedef std::basic_ostream<char> ostream;
	typedef std::basic_ostream<wchar_t> wostream;
	class apartment;

	void write_int_to_stream(wostream &, int);


	/// This is the interface which all objects implement.
	/** \ref dynamic::var contains one of these, and all methods in var (and var_methods)
		call this object.

		For most implementations of this interface, most of these methods don't do
		anything, or throw the \ref dynamic::not_supported exception. 
		That's the crux of dynamic typing - you only know what operations are supported
		at run-time.
		\ingroup impl
	*/
	class DYNAMIC_API var_impl : public internal::variant_base
	{
	public:
		virtual ~var_impl();

		/// Call the object with no arguments.
		virtual var call();

		/// Call the object with 1 argument.
		virtual var call(const var & a0);

		/// Call the object with 2 arguments.
		virtual var call(const var & a0, const var & a1);

		/// Call the object with 3 arguments.
		virtual var call(const var & a0, const var & a1, const var & a2);

		/// Call the object with 4 arguments.
		virtual var call(const var & a0, const var & a1, const var & a2, const var & a3);

		/// Call the object with 5 arguments.
		virtual var call(const var & a0, const var & a1, const var & a2, const var & a3, const var & a4);

		/// Call the object with 6 arguments.
		virtual var call(const var & a0, const var & a1, const var & a2, const var & a3, const var & a4, const var & a5);

		/// Call the object with 7 arguments.
		virtual var call(const var & a0, const var & a1, const var & a2, const var & a3, const var & a4, const var & a5, const var & a6);

		/// Call the object with 8 arguments.
		virtual var call(const var & a0, const var & a1, const var & a2, const var & a3, const var & a4, const var & a5, const var & a6, const var & a7);

		/// Call the object with 9 arguments.
		virtual var call(const var & a0, const var & a1, const var & a2, const var & a3, const var & a4, const var & a5, const var & a6, const var & a7, const var & a8);

		/// Call the object with 10 arguments.
		virtual var call(const var & a0, const var & a1, const var & a2, const var & a3, const var & a4, const var & a5, const var & a6, const var & a7, const var & a8, const var & a9);

		/// Return the maximum number arguments that the object can be called with
		/** Returns -1 if the object cannot be called.*/
		virtual int max_args();

		/// Calls the given method with no arguments.
		virtual var member_call(const char*);

		/// Calls the given method with 1 arguments.
		virtual var member_call(const char*, const var & a0);

		/// Calls the given method with 2 arguments.
		virtual var member_call(const char*, const var & a0, const var & a1);

		/// Calls the given method with 3 arguments.
		virtual var member_call(const char*, const var & a0, const var & a1, const var & a2);

		/// Calls the given method with 4 arguments.
		virtual var member_call(const char*, const var & a0, const var & a1, const var & a2, const var & a3);

		/// Calls the given method with 5 arguments.
		virtual var member_call(const char*, const var & a0, const var & a1, const var & a2, const var & a3, const var & a4);

		/// Calls the given method with 6 arguments.
		virtual var member_call(const char*, const var & a0, const var & a1, const var & a2, const var & a3, const var & a4, const var & a5);

		/// Calls the given method with 7 arguments.
		virtual var member_call(const char*, const var & a0, const var & a1, const var & a2, const var & a3, const var & a4, const var & a5, const var & a6);

		/// Calls the given method with 8 arguments.
		virtual var member_call(const char*, const var & a0, const var & a1, const var & a2, const var & a3, const var & a4, const var & a5, const var & a6, const var & a7);

		/// Calls the given method with 9 arguments.
		virtual var member_call(const char*, const var & a0, const var & a1, const var & a2, const var & a3, const var & a4, const var & a5, const var & a6, const var & a7, const var & a8);

		/// Calls the given method with 10 arguments.
		virtual var member_call(const char*, const var & a0, const var & a1, const var & a2, const var & a3, const var & a4, const var & a5, const var & a6, const var & a7, const var & a8, const var & a9);

		/// Returns the comparison index (type identified) of the var.
		virtual var_cmp_index comparison_index();

		/// Compares this object with another.
		/** vars are usually compared first on comparison_index, then calls compare2() for
			objects of the same type */
		virtual var_cmp_result compare(const var & other);

		/// Compares two objects of the same comparison_index().
		virtual var_cmp_result compare2(const var & other);
		
		/// Gets the given member.
		virtual var get_member(var const &);

		/// Sets the given member.
		virtual void set_member(var const &, var const &);

		/// Gets the given member (string index).
		/** The string index is separate for efficiency */
		virtual var get_member(const char*);

		/// Gets the given member (integer index).
		/** The int index is separate for efficiency */
		virtual var get_member(int);

		/// Sets the given member (string index).
		virtual void set_member(const char*, var const&);

		/// Sets the given member (integer index).
		virtual void set_member(int, var const&);

		/// Pushes the value onto the back.
		virtual void push_back(var const&);

		/// Removes a value from the back and returns it.
		virtual var pop_back();

		/// Pushes the value onto the front.
		virtual void push_front(var const&);

		/// Removes a value from the front and returns it.
		virtual var pop_front();

		/// Inserts an item.
		virtual void insert(const var&);

		/// Inserts a pair.
		virtual void insert(const var&, const var&);

		/// Retrieve the first/front item.
		virtual var front();

		/// Get the last/back item.
		virtual var back();

		/// Returns an iterator to the begin (default=null).
		virtual var begin();

		/// Returns an iterator to the end (default=null)
		virtual var end();

		/// Returns the number of items in the data structure (default=0).
		/** \todo Should be std::size_t or even var? */
		virtual int size();	

		/// Returns whether the container is empty (default=true).
		virtual bool empty();

		/// Returns the reverse begin iterator.
		virtual var rbegin();

		/// Returns the reverse end iterator.
		virtual var rend();

		/// Erases all items (default=no effect).
		virtual void clear();

		/// Returns whether the object contains 
		virtual bool contains(const var&);

		/// Erases the specified item, but does not throw on error.
		virtual void erase(const var&);

		/// Adds the members of one object to another.
		virtual void mixin(const var&);

		/// Returns the number of bound arguments.
		virtual int bind_args();

		/// Outputs to a narrow stream.
		virtual void output(ostream&);

		/// Outputs to a wide stream.
		virtual void output(wostream&);

		/// Short output to a narrow stream.
		/** This call would not be recursive, whereas output() is */
		virtual void short_output(ostream&);

		/// Short output to a wide stream.
		virtual void short_output(wostream&);

		/// Converts to an integer (default=0).
		virtual int as_int();

		/// Converts to a double (default=0).
		virtual double as_double();

		/// Converts to a bool (default=false).
		virtual bool as_bool();

		/// Converts to a pointer (default=0).
		virtual void * as_ptr();

		/// Dereferences if the object is an iterator.
		virtual var deref();

		/// Obtains the key from an iterator.
		virtual var key();

		/// Obtains the value from an iterator.
		virtual var value();

		/// Clones the object.
		virtual var clone();

		/// Resizes the object (for array and string containers).
		virtual void resize(std::size_t);	// ?? Should be a var?

		/// Addition operator.
		virtual var op_add(const var &);

		/// Return a container of keys.
		virtual var keys();

		/// Return a container of values.
		virtual var values();

		/// Unary minus.
		virtual var op_neg();

		/// Unary add (default is to clone).
		virtual var op_pos();

		/// Subtraction operator.
		virtual var op_sub(const var &);

		/// Multiplication operator.
		virtual var op_mul(const var &);

		/// Division operator.
		virtual var op_div(const var &);

		/// Modulus operator.
		virtual var op_mod(const var &);

		/// Left-shift operator.
		virtual var op_lshift(const var&);

		/// Right-shift operator.
		virtual var op_rshift(const var&);

		/// Bitwisze and operator.
		virtual var op_and(const var &);

		/// Bitwise or operator.
		virtual var op_or(const var &);

		/// Bitwise xor operator.
		virtual var op_xor(const var &);

		/// Bitwise inverse operator.
		virtual var op_inv();

		/// Increment operator.
		virtual void op_inc();

		/// Decrement operator.
		virtual void op_dec();

		/// Add with assignment.
		virtual void assign_add(const var&);

		/// Subtract with assignment.
		virtual void assign_sub(const var&);

		/// Multiplication with assignment.
		virtual void assign_mul(const var&);

		/// Division with assign.
		virtual void assign_div(const var&);

		/// Modulus with assign.
		virtual void assign_mod(const var&);

		/// Left shift with assign.
		virtual void assign_lshift(const var&);

		/// Right shift with assign.
		virtual void assign_rshift(const var&);

		/// Bitwise and with assign.
		virtual void assign_and(const var&);

		/// Bitwise or with assign.
		virtual void assign_or(const var&);

		/// Bitwise xor with assign.
		virtual void assign_xor(const var&);

		/// Increment a member.
		virtual var member_inc(const char * member);

		/// Decrement a member.
		virtual var member_dec(const char * member);

		/// Add an integer to a member.
		virtual var member_inc(const char * member, int);

		/// Subtract an integer from a member.
		virtual var member_dec(const char * member, int);

		/// Add to a member.
		virtual var member_add(const char * member, const var &);

		/// Subtract from a member.
		virtual var member_sub(const char * member, const var &);

		/// Return the class name.
		virtual std::string class_name()=0;

		/// Pickle the object.
		/** \see dynamic::pickle() function. */
		virtual void pickle(pickler&);

		/// Unpickle the object.
		/** \see dynamic::unpickle() function */
		virtual void unpickle(unpickler&);

		/// Convert the object to a root object.
		/** TODO: change this mechanism */
		virtual var as_root();	

		/// Convert this object to a non-root object.
		virtual var as_nonroot();	

		/// Call this to mark the object as reachable (so that the garbage collector does not destroy it).
		/** Call this method from dynamic::gc::gc_object::mark_children() method */
		virtual void mark_reachable(gc::garbage_collector&);

		/// Retrieve the shared variable or null.
		virtual shared_var_impl * shared_var();

		/// Returns a proxy to this object.
		virtual var proxy();

		/// Returns an enumerator for the contents (default null).
		/** Enumerators are iterators which implement the ++ operator
			to advance them, and var::as_bool() to tell you when the iterator
			has reached the end.
		*/
		virtual var enumerator();

		/// Returns a reverse enumerator for the contents (default null).
		virtual var reverse_enumerator();

		/// Reserves (default no effect).
		virtual void reserve(std::size_t);

		/// Returns the capacity of the container before needing to reallocate (default=0).
		virtual std::size_t capacity();

		/// Obtains the range represented by this object (default=0).
		virtual void get_range(std::size_t container_size, std::pair<std::size_t,std::size_t> & out);
	};
}
